package com.randb.easyhttp.model;

import android.text.TextUtils;

import com.randb.easyhttp.body.ProgressResponseCallback;

import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import okhttp3.MediaType;

/**
 * User: RandBII
 * Date: 2020/5/8
 * Description:
 */
public class HttpParams implements Serializable {

    public LinkedHashMap<String, String> urlParamsMap;
    public LinkedHashMap<String, List<FileWrapper>> fileParamsMap;

    public HttpParams() {
        init();
    }

    public HttpParams(String key, String value) {
        init();
        put(key, value);
    }


    private void init() {
        urlParamsMap = new LinkedHashMap<>();
        fileParamsMap = new LinkedHashMap<>();
    }

    public void put(String key, String value) {
        urlParamsMap.put(key, value);
    }

    public void put(HttpParams params) {
        if (params == null) return;
        if (params.urlParamsMap != null && !params.urlParamsMap.isEmpty()) {
            this.urlParamsMap = params.urlParamsMap;
        }
        if (params.fileParamsMap != null && !params.fileParamsMap.isEmpty()) {
            this.fileParamsMap = params.fileParamsMap;
        }

    }

    public void put(Map<String, String> maps) {
        if (maps == null) return;
        urlParamsMap.putAll(maps);
    }

    public <T extends File> void put(String key, T file, ProgressResponseCallback callback) {
        put(key, file, file.getName(), callback);
    }

    public void put(String key, Byte[] bytes, String name, ProgressResponseCallback callback) {
        put(key, bytes, name, guessMimeType(name), callback);
    }


    public <T extends File> void put(String key,
                                     T file,
                                     String name,
                                     ProgressResponseCallback callback) {
        put(key, file, name, guessMimeType(name), callback);
    }

    public <T extends InputStream> void put(String key, T file,
                                            String name,
                                            ProgressResponseCallback callback) {
        put(key, file, name, guessMimeType(name), callback);
    }


    public void put(String key, FileWrapper wrapper) {
        if (key != null && wrapper != null) {
            put(key, wrapper.file, wrapper.fileName, wrapper.contentType, wrapper.callback);
        }
    }


    @SuppressWarnings("unchecked")
    public <T> void put(String key, T content, String fileName,
                        MediaType mediaType,
                        ProgressResponseCallback callback) {
        if (key != null) {
            List<FileWrapper> fileWrappers = fileParamsMap.get(key);
            if (fileWrappers == null) {
                fileWrappers = new ArrayList<>();
                fileParamsMap.put(key, fileWrappers);
            }
            fileWrappers.add(new FileWrapper(content, fileName, mediaType, callback));
        }
    }


    public <T extends File> void putFileParams(String key, List<T> files,
                                               ProgressResponseCallback callback) {
        if (!TextUtils.isEmpty(key) && !files.isEmpty()) {
            for (File f : files) {
                put(key, f, callback);
            }
        }
    }


    public void putFileWrapperParams(String key, List<FileWrapper> wrappers) {
        if (!TextUtils.isEmpty(key) && !wrappers.isEmpty()) {
            for (FileWrapper wrapper : wrappers) {
                put(key, wrapper);
            }
        }
    }

    public void remove(String key) {
        removeUrlParam(key);
        removeFileParam(key);
    }

    private void removeFileParam(String key) {
        fileParamsMap.remove(key);
    }

    private void removeUrlParam(String key) {
        urlParamsMap.remove(key);
    }

    public void clear() {
        urlParamsMap.clear();
        fileParamsMap.clear();
    }


    private MediaType guessMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        path = path.replace("#", "");
        String contentType = fileNameMap.getContentTypeFor(path);
        if (TextUtils.isEmpty(contentType)) {
            contentType = "application/octet-stream";
        }
        return MediaType.parse(contentType);
    }


    public static class FileWrapper<T> {
        public T file;
        public String fileName;
        public long fileSize;
        public MediaType contentType;
        public ProgressResponseCallback callback;

        public FileWrapper(T file, String fileName,
                           MediaType contentType, ProgressResponseCallback callback) {
            this.file = file;
            this.fileName = fileName;
            this.contentType = contentType;
            if (file instanceof File) {
                this.fileSize = ((File) file).length();
            } else if (file instanceof byte[]) {
                this.fileSize = ((byte[]) file).length;
            }
            this.callback = callback;

        }

        @Override
        public String toString() {
            return "FileWrapper{" +
                    "file=" + file +
                    ", fileName='" + fileName + '\'' +
                    ", fileSize=" + fileSize +
                    ", contentType=" + contentType +
                    ", callback=" + callback +
                    '}';
        }
    }


    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        for (ConcurrentHashMap.Entry<String, String> entry : urlParamsMap.entrySet()) {
            if (builder.length() > 0) builder.append("&");
            builder.append(entry.getKey()).append("=").append(entry.getValue());
        }

        for (ConcurrentHashMap.Entry<String, List<FileWrapper>> entry : fileParamsMap.entrySet()) {
            if (builder.length() > 0) builder.append("&");
            builder.append(entry.getKey()).append("=").append(entry.getValue());
        }
        return builder.toString();
    }
}
